#pragma once
#include "Tetrisstd.h"
#include "GFXUtil.h"
#include "CInput.h"
#include "tinyxml2.h"
#include "FmodAudio.h"
#include <time.h>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>
#include <memory>

typedef std::shared_ptr<CSprite> SpritePtr;

struct Vec2
{
	
	Vec2() { x=0; y=0; }
	Vec2(int xval, int yval)
		: x(xval), y(yval) { }

	int x;
	int y;
};

struct TetrisBlock
{
	Vec2 Position;
	std::vector<Vec2> Parts;
	std::string ImageName;
	int Width, Height;
};

struct GameLevel
{
	int Length;
	double Speed;
	double Factor;
};

enum GameEvent
{
	EVENT_MOVE_LEFT,
	EVENT_MOVE_RIGHT,
	EVENT_MOVE_DOWN,
	EVENT_ROTATE,
	EVENT_JUMP_DOWN
};

enum GameState
{
	RUNNING,
	DELETE_ROWS,
	GAME_OVER,
};

class Game
{
	bool m_bMusic;
	bool m_bRunning;
	HWND m_hWnd;

	CSprite* m_sprite;
	CSprite* m_inactiveSprite;
	CSprite* m_background;
	CSprite* m_gameOverLayer;
	TetrisBlock* m_block;
	TetrisBlock* m_nextBlock;

	GameState m_state;

	IDirect3D9* m_d3d;
	IDirect3DDevice9* m_device;
	IDirect3DSurface9 *m_backbuffer;
	ID3DXSprite *m_spriteHandler;
	D3DPRESENT_PARAMETERS m_d3dpp;
	CInput* m_input;
	Audio* m_audio;
	ID3DXFont* m_font;

	Sample* m_FXdeleteLine;
	Sample* m_FXrotate;
	Sample* m_FXjump;
	Sample* m_FXnewLevel;
	Sample* m_FXgameOver;
	Sample* m_music;

	int m_fieldWidth;
	int m_fieldHeight;
	int m_cellWidth;
	int m_cellHeight;

	Vec2 m_nextBlockPos;
	Vec2 m_fieldPosition;
	Vec2 m_fieldSize;

	std::vector<std::vector<int>> m_field; //rows /cols
	std::vector<int> m_fullRows;
	std::vector<TetrisBlock> m_blockTypes;
	std::vector<GameLevel> m_levels;
	std::map<std::string, SpritePtr> m_images;
	int m_currentLevel;
	int m_blockCount;
	double m_points;

	int m_frameRate;

public:
	Game();
	~Game();

	bool Preload();
	bool Init(HWND hWnd);
	void Update(double deltaSecs);
	void Render();
	void Close();
	void SendEvent(GameEvent gameEvent);

	void SetRunning(bool running) { m_bRunning = running; }
	bool IsRunning() { return m_bRunning; }
	void KeyDown(int key);
	void KeyUp(int Key);

private:
	bool InitD3D();
	void PrintBlock();
	void ResetMovingParts();
	bool DropBlock();
	void SpawnBlock();
	bool MoveBlock(int dir);
	bool RotateBlock();
	void TestRows();
	void DeleteRow(int row);
	void RenderField();
	void RenderNextBlock();
	bool IsGameOver();
	void AnimateRows(double deltaSecs);
	bool LoadGame(const char* filename);
	bool LoadBlockTypes(const char* filename);
	void UpdateFrameRate(double deltaSecs);
	void StartNewGame();
};